package com.optitronics.service.impl;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;

import com.optitronics.beans.OrderItem;
import com.optitronics.beans.Reseller;
import com.optitronics.beans.ResellerOrder;
import com.optitronics.beans.SystemProperties;
import com.optitronics.service.ReportService;
import com.optitronics.util.JasperView;
import com.optitronics.util.OptitronicsConstants;
import com.optitronics.util.OptitronicsUtils;

@Service
public class ReportServiceImpl implements ReportService {

	private Log logger = LogFactory.getLog(this.getClass());

	@Autowired
	private MessageSource messageSource;

	@Value("${excel.target.location}")
	private String excelTargetLocation;

	@Value("${excel.template.file}")
	private String templateFileName;

	/**
	 * Generating invoice reports
	 * 
	 * @param orderId
	 */
	public Map<String, Object> printInvoiceReport(Integer orderId, String applicationFolder) {
		logger.info(OptitronicsUtils.getLoggerPrefix() + ": " + "Generating invoice report, orderId: " + orderId);

		Map<String, Object> parameterMap = new HashMap<String, Object>();
		String logoLocation = applicationFolder + File.separator + "images" + File.separator + "optronics_logo.jpg";

		String reportName = messageSource
				.getMessage("label.report.invoice.name", null, LocaleContextHolder.getLocale());
		parameterMap.put(JasperView.REPORT_FILE_NAME, reportName);

		ResellerOrder resellerOrder = ResellerOrder.findResellerOrder(orderId);
		List<OrderItem> orderItems = OrderItem.findOrderItems(orderId);

		parameterMap.put("resellerName", resellerOrder.getReseller().getName());
		parameterMap.put("resellerAddress", resellerOrder.getReseller().getAddress());
		parameterMap.put("resellerCity", resellerOrder.getReseller().getCity());
		parameterMap.put("resellerTaxNumber", resellerOrder.getReseller().getTaxNumber());
		parameterMap.put("invoiceNumber", resellerOrder.getOrderNumber());
		parameterMap.put("logoLocation", new File(logoLocation));

		SimpleDateFormat format = new SimpleDateFormat(OptitronicsConstants.INVOICE_DATE_FORMAT);
		parameterMap.put("orderDate", format.format(resellerOrder.getOrderDate()));

		parameterMap.put("invoiceNumber", resellerOrder.getOrderNumber());

		parameterMap.put("totalAmountWithoutTax", resellerOrder.getTotalAmountWithoutTax());
		parameterMap.put("totalAmountWithTax", resellerOrder.getTotalAmountWithTax());
		parameterMap.put("taxPercent", OptitronicsConstants.TAX_PERCENT);

		parameterMap.put("systemProperties", SystemProperties.getSystemPropertiesAsMap());

		JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(orderItems);
		parameterMap.put("dataSource", dataSource);

		return parameterMap;
	}

	/**
	 * Generating excel for given orderId
	 * 
	 * @param orderId
	 * @throws Exception
	 */
	public List<String> generateOrderExcels(Integer orderId) throws Exception {
		logger.info(OptitronicsUtils.getLoggerPrefix() + ": " + "Generating order excels, orderId: " + orderId);
		List<String> xlsFileNames = new ArrayList<String>();

		List<OrderItem> orderItems = OrderItem.findOrderItems(orderId);
		for (OrderItem orderItem : orderItems) {
			String xlsFileName = generateOrderItemExcel(orderItem);
			xlsFileNames.add(xlsFileName);
		}

		return xlsFileNames;
	}

	/**
	 * loads pdf file names for order
	 * 
	 * @param orderId
	 * @return
	 * @throws Exception
	 */
	public List<String> getPDFsForOrder(Integer orderId) throws Exception {
		logger.info(OptitronicsUtils.getLoggerPrefix() + ": " + "loading pdf file names, orderId: " + orderId);
		List<String> pdfFileNames = new ArrayList<String>();

		List<OrderItem> orderItems = OrderItem.findOrderItems(orderId);
		for (OrderItem orderItem : orderItems) {
			if (OptitronicsConstants.ORDER_TYPE_RENEWAL.equals(orderItem.getPriceType())) {
				String fileName = getOrderItemFileName(orderItem) + ".pdf";
				pdfFileNames.add(fileName);
			}
		}

		return pdfFileNames;
	}

	public String getOrderItemFileName(OrderItem orderItem) {
		String outputFileName = orderItem.getResellerOrder().getOrderNumber() + "_" + orderItem.getOrdinal();
		return excelTargetLocation + File.separator + outputFileName;
	}

	private String generateOrderItemExcel(OrderItem orderItem) throws Exception {

		logger.info(OptitronicsUtils.getLoggerPrefix() + ": " + "Generating order item excel, orderItemId: "
				+ orderItem.getId());

		String outputFullFileName = getOrderItemFileName(orderItem) + ".xls";

		File outputFile = new File(outputFullFileName);
		WorkbookSettings wbSettings = new WorkbookSettings();

		wbSettings.setLocale(new Locale("en", "EN"));

		Workbook templateWorkbook = Workbook.getWorkbook(new File(templateFileName));

		WritableWorkbook workbook = Workbook.createWorkbook(outputFile, templateWorkbook, wbSettings);
		WritableSheet excelSheet = workbook.getSheet(0);

		addText(excelSheet, 0, 1, orderItem.getBuyerName());
		addText(excelSheet, 1, 1, orderItem.getBuyerEmail());
		addText(excelSheet, 3, 1, orderItem.getBuyerCity());

		addText(excelSheet, 0, 3, orderItem.getBuyerContactPerson());
		addText(excelSheet, 1, 3, orderItem.getBuyerPhone());
		addText(excelSheet, 3, 3, orderItem.getBuyerAddress() + ", " + orderItem.getBuyerCity());

		addText(excelSheet, 0, 5, orderItem.getProduct().getName());
		addText(excelSheet, 1, 5, orderItem.getQuantity().toString());
		Reseller reseller = orderItem.getResellerOrder().getReseller();
		String resellerCode = reseller.getCode() != null ? reseller.getCode() : "";
		addText(excelSheet, 1, 7, resellerCode);

		if (OptitronicsConstants.ORDER_TYPE_NEW.equals(orderItem.getPriceType())
				|| OptitronicsConstants.ORDER_TYPE_RENEWAL.equals(orderItem.getPriceType())) {

			boolean renewal = OptitronicsConstants.ORDER_TYPE_RENEWAL.equals(orderItem.getPriceType());
			String renewalString = renewal ? "DA" : "NE";
			addText(excelSheet, 2, 5, renewalString);
		} else {
			String renewalString = "NE";
			addText(excelSheet, 2, 5, renewalString);
			String messageKey = "label.order.type." + orderItem.getPriceType();
			String orderTypeString = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale());
			addText(excelSheet, 3, 5, orderTypeString);
		}

		templateWorkbook.close();

		workbook.write();
		workbook.close();
		return outputFullFileName;
	}

	private void addText(WritableSheet sheet, int column, int row, String text) throws RowsExceededException,
			WriteException {

		Label label = new Label(column, row, text);
		sheet.addCell(label);
	}
}
